package server

import (
	"context"
	"github.com/pingcap-incubator/tinykv/kv/storage"
	"github.com/pingcap-incubator/tinykv/proto/pkg/kvrpcpb"
	log "github.com/sirupsen/logrus"
)

// The functions below are Server's Raw API. (implements TinyKvServer).
// Some helper methods can be found in sever.go in the current directory

// RawGet return the corresponding Get response based on RawGetRequest's CF and Key fields
// RawGet 根据 RawGetRequest 的 CF 和 Key 字段返回对应的 Get 响应
func (server *Server) RawGet(_ context.Context, req *kvrpcpb.RawGetRequest) (*kvrpcpb.RawGetResponse, error) {
	// Your Code Here (1).
	//get data
	cf, key := req.GetCf(), req.GetKey()
	//define response
	var resp kvrpcpb.RawGetResponse
	//get reader
	reader, err := server.storage.Reader(req.GetContext())
	if err != nil {
		resp.Error = err.Error()
		log.Errorln("[RawGet]", err)
		return &resp, err
	}
	defer reader.Close()
	//get result
	result, err := reader.GetCF(cf, key)
	if err != nil {
		resp.Error = err.Error()
		log.Errorln("[RawGet]", err)
		return &resp, err
	}
	//return resp
	resp.Value = result
	if len(result) == 0 {
		resp.NotFound = true
	}
	return &resp, nil
}

// RawPut puts the target data into storage and returns the corresponding response
// RawPut 将目标数据放入存储并返回相应的响应
func (server *Server) RawPut(_ context.Context, req *kvrpcpb.RawPutRequest) (*kvrpcpb.RawPutResponse, error) {
	// Your Code Here (1).
	// Hint: Consider using Storage.Modify to store data to be modified
	//get data
	cf, key, value := req.GetCf(), req.GetKey(), req.GetValue()
	//define response
	var resp kvrpcpb.RawPutResponse
	//make Modify
	mod := make([]storage.Modify, 1)
	mod[0] = storage.Modify{
		Data: storage.Put{
			Cf:    cf,
			Key:   key,
			Value: value,
		},
	}
	//execute write
	err := server.storage.Write(req.GetContext(), mod)
	if err != nil {
		resp.Error = err.Error()
		log.Errorln("[RawPut]", err)
	}
	return &resp, nil
}

// RawDelete delete the target data from storage and returns the corresponding response
// RawDelete 从存储中删除目标数据并返回相应的响应
func (server *Server) RawDelete(_ context.Context, req *kvrpcpb.RawDeleteRequest) (*kvrpcpb.RawDeleteResponse, error) {
	// Your Code Here (1).
	// Hint: Consider using Storage.Modify to store data to be deleted
	//get data
	cf, key := req.GetCf(), req.GetKey()
	//define response
	var resp kvrpcpb.RawDeleteResponse
	//make Modify
	mod := make([]storage.Modify, 1)
	mod[0] = storage.Modify{
		Data: storage.Delete{
			Key: key,
			Cf:  cf,
		},
	}
	//execute write
	err := server.storage.Write(req.GetContext(), mod)
	if err != nil {
		resp.Error = err.Error()
		log.Errorln("[RawDelete]", err)
	}

	return &resp, err
}

// RawScan scan the data starting from the start key up to limit. and return the corresponding result
// RawScan 扫描数据从开始键开始直到限制。 并返回相应的结果
func (server *Server) RawScan(_ context.Context, req *kvrpcpb.RawScanRequest) (*kvrpcpb.RawScanResponse, error) {
	// Your Code Here (1).
	// Hint: Consider using reader.IterCF
	//get data
	cf, start, limit := req.GetCf(), req.StartKey, req.Limit
	//define response
	var resp kvrpcpb.RawScanResponse
	reader, err := server.storage.Reader(req.GetContext())
	if err != nil {
		resp.Error = err.Error()
		log.Errorln("[RawScan]", err)
	}
	defer reader.Close()
	//get IterCF
	iter := reader.IterCF(cf)
	defer iter.Close()
	//make pair
	pair := make([]*kvrpcpb.KvPair, 0, limit)
	var i uint32 = 0
	//scan all data util on limit
	for iter.Seek(start); iter.Valid() && i < limit; iter.Next() {
		item := iter.Item()
		key := item.Key()
		value, _ := item.Value()
		kvPair := kvrpcpb.KvPair{
			Key:   key,
			Value: value,
		}
		pair = append(pair, &kvPair)
		i++
	}
	resp.Kvs = pair
	return &resp, err
}
